package discovery

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/grandcat/zeroconf"
)

// Node info
type Node struct {
	IP     string            `json:"ip"`
	Port   int               `json:"port"`
	Host   string            `json:"host"`
	Params map[string]string `json:"params"`
}

func (n *Node) String() string {
	buf, _ := json.Marshal(n)

	return string(buf)
}

// Register node
func Register(ctx context.Context, name, ip string, port int, text []string) (*zeroconf.Server, error) {

	instance := fmt.Sprintf("%s:%d", ip, port)
	serviceName := name
	host := ip
	ips := []string{ip}
	domain := "local."
	s, err := zeroconf.RegisterProxy(instance, serviceName, domain, port, host, ips, text, nil)
	if err != nil {
		return nil, err
	}

	return s, nil
}

// Browse node info
func Browse(ctx context.Context, name string, cb func(node *Node)) error {

	resolver, err := zeroconf.NewResolver(nil)
	if err != nil {
		return err
	}

	chResults := make(chan *zeroconf.ServiceEntry)

	serviceName := name
	domain := "local."
	err = resolver.Browse(ctx, serviceName, domain, chResults)
	if err != nil {
		return err
	}

	for {
		select {
		case <-ctx.Done():
			return fmt.Errorf("Server stopd")
		case event := <-chResults:
			if event != nil && len(event.AddrIPv4) > 0 {
				params := text2params(event.Text)
				if len(params) == 0 {
					break
				}

				cb(&Node{
					IP:     event.AddrIPv4[0].String(),
					Port:   event.Port,
					Host:   event.HostName,
					Params: params,
				})
			}
		}
		time.Sleep(time.Microsecond * 200)
	}
}

func text2params(texts []string) map[string]string {

	params := make(map[string]string)

	for _, text := range texts {
		textArr := strings.Split(text, "=")
		if len(textArr) == 2 {
			params[textArr[0]] = textArr[1]
		}
	}

	return params
}
